#include<curl/curl.h>
#include<iostream>
#include<sstream>

//libcurl 读取邮件内容时会回调此函数，
//用于从字符串流中读取数据并传递给 curl

// buffer：curl 提供的缓冲区，用于存放读取的数据
// size：每个数据单元的大小（字节）
// nitems：数据单元的数量 → 总读取字节数 = size * nitems
// userdata：用户自定义数据（这里是存放邮件内容的 stringstream）
size_t callback(char *buffer, size_t size, size_t nitems, void *userdata) {
	// 将 userdata 转换为 stringstream 指针（之前传入的邮件内容流）
	std::stringstream *ss = (std::stringstream*)userdata;
	// 从字符串流中读取数据到 buffer，读取长度为 size * nitems
	ss->read(buffer, size * nitems);
	// 返回实际读取的字节数（供 curl 判断是否读取完毕）
	return ss->gcount();
}

int main()
{
	//1.邮件配置参数定义
	// 邮箱账号密码（163 邮箱的登录账号和授权码，注意：密码通常是 SMTP 授权码而非登录密码）
	const std::string username = "18843511697@163.com";
    const std::string password = "YYicPq7PiGZNtUnx";//邮箱的 SMTP 授权码
	// SMTP 服务器地址：smtps 表示加密连接（SSL），端口 465 是 qq 邮箱的 SMTP 加密端口
    const std::string url = "smtps://smtp.163.com:465";
	// 发件人邮箱（需与 username 一致）
    const std::string from = "18843511697@163.com";
	//// 收件人邮箱
    const std::string to = "18843511697@163.com";


	//2.初始化 libcurl 全局环境
	// 初始化 libcurl 全局配置（如 SSL 库、DNS 等），CURLOPT_GLOBAL_DEFAULT 表示默认配置
	auto ret = curl_global_init(CURL_GLOBAL_DEFAULT);
	if (ret != CURLE_OK) {  // 检查初始化是否成功（CURLE_OK 表示成功）
	    // 打印错误信息：curl_easy_strerror 将错误码转换为可读字符串
	    std::cout << "curl_global_init failed: " << curl_easy_strerror(ret) << std::endl;
	    return -1;
	}


	//3.创建 curl 操作句柄
	// 创建一个 curl 句柄（类似操作上下文），后续所有配置和操作都基于此句柄
	auto curl = curl_easy_init();
	if (curl == nullptr) {  // 检查句柄是否创建成功
	    std::cout << "curl_easy_init failed" << std::endl;
	    return -1;
	}

	//4.配置 SMTP 请求参数
	// 设置 SMTP 服务器地址（如 smtps://smtp.qq.com:465）
	ret = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_URL failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}	

	// 设置 SMTP 登录用户名（发件人邮箱）
	ret = curl_easy_setopt(curl, CURLOPT_USERNAME, username.c_str());
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_USERNAME failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}	

	// 设置 SMTP 登录密码（163 邮箱需使用 SMTP 授权码）
	ret = curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str());
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_PASSWORD failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}

	// 设置发件人邮箱（需与用户名一致）
	ret = curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from.c_str());
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_MAIL_FROM failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}

	// 创建收件人列表（curl_slist 是 libcurl 用于存储字符串列表的结构）
	struct curl_slist *cs = nullptr;
	// 向列表中添加收件人（多个收件人需多次调用 append）
	cs = curl_slist_append(cs, to.c_str());
	// 设置收件人列表
	ret = curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, cs);
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_MAIL_RCPT failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}

	// 创建字符串流，用于构建邮件内容（遵循 SMTP 协议格式）
	std::stringstream ss;
	// 邮件主题（Subject 字段）
	ss << "Subject: 验证码\r\n";
	// 邮件内容类型：text/html 表示正文是 HTML 格式（默认是纯文本 text/plain）
	ss << "Content-Type: text/html\r\n";
	// 空行：SMTP 协议要求 headers 和 body 之间必须有一个空行（\r\n）
	ss << "\r\n";
	// HTML 格式的邮件正文（包含验证码信息）
	ss << "<html><body><p>你的验证码: <b>5678</b></p><p>验证码将在5分钟后失效.</p></body></html>\r\n";

	// 设置读取数据的来源（这里是存放邮件内容的 stringstream）
	ret = curl_easy_setopt(curl, CURLOPT_READDATA, (void*)&ss);
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_READDATA failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}

	// 设置读取数据的回调函数（curl 会调用此函数从 ss 中读取邮件内容）
	ret = curl_easy_setopt(curl, CURLOPT_READFUNCTION, callback);
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_READFUNCTION failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}

	// 启用上传模式（SMTP 发送邮件本质是向服务器上传数据）
	ret = curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);  // 1L 表示启用
	if (ret != CURLE_OK) {
	    std::cout << "curl_easy_setopt CURLOPT_UPLOAD failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}

	// 执行 curl 操作（发送邮件）
	ret = curl_easy_perform(curl);
	if (ret!= CURLE_OK) {  // 检查发送是否成功
	    std::cout << "curl_easy_perform failed: " 
			<< curl_easy_strerror(ret) << std::endl;
	    return -1;
	}

	// 释放收件人列表内存
	curl_slist_free_all(cs);
	// 释放 curl 句柄
	curl_easy_cleanup(curl);
	// 清理 libcurl 全局环境
	curl_global_cleanup();
}